#include "array.h"

static const size_t array_enlarging_cap = 4;
/// @brief 初始化动态数组
/// @param deinit_before 释放元素函数
/// @return array_t *变量
array_t *array_init(array_data_deinit_impl deinit_before)
{
    array_t *ret = malloc(sizeof(array_t));
    if (ret == NULL)
        goto fail0;
    ret->cap = array_enlarging_cap;
    ret->len = 0;
    ret->deinit_before = deinit_before;
    ret->datas = malloc(sizeof(void *));
    if (ret->datas == NULL)
    {
        free(ret);
        ret = NULL;
    }

fail0:
    return ret;
}
/// @brief 扩容动态数组
/// @param ptr array_t *变量地址
/// @param enlarging_len 扩容长度
/// @return
static inline int __array_enlarging(array_t **ptr, size_t enlarging_len)
{
    if (*ptr == NULL || enlarging_len <= 0)
        return -1;
    array_t *arr = *ptr;
    size_t cap = arr->cap + enlarging_len;
    void **datas = malloc(sizeof(void *) * cap);
    if (datas == NULL)
        return -2;
    for (size_t i = 0; i < arr->len; i++)
        datas[i] = arr->datas[i];
    free(arr->datas);
    arr->datas = datas;
    arr->cap = cap;
    return 0;
}

/// @brief 追加元素到动态数组尾部
/// @param arr 动态数组变量
/// @param data 元素地址
/// @return
int array_add(array_t *arr, void *data)
{
    if (arr == NULL)
        return -1;
    if (arr->len + 1 >= arr->cap)
    {
        int ret = __array_enlarging(&arr, arr->cap + array_enlarging_cap);
        if (ret)
            return ret;
    }
    arr->datas[arr->len++] = data;
    return 0;
}

/// @brief 删除指定下标元素
/// @param arr
/// @param index 指定下标
/// @param del 是否对指定元素执行deinit_before
/// @return
int array_delete(array_t *arr, size_t index, int del)
{
    if (arr == NULL || index >= arr->len)
        return -1;

    if (del != 0 && arr->deinit_before != NULL)
        arr->deinit_before(arr->datas[index]);
    // 批量前移
    for (size_t i = index; i < arr->len; i++)
        arr->datas[i] = arr->datas[i + 1];
    arr->len--;
    return 0;
}

/// @brief 更新指定下标元素
/// @param arr
/// @param index 指定下标
/// @param data 新元素地址
/// @param del 是否对指定旧元素执行deinit_before
/// @return
int array_update(array_t *arr, size_t index, void *data, int del)
{
    if (arr == NULL || index >= arr->len)
        return -1;
    if (del != 0 && arr->deinit_before != NULL)
        arr->deinit_before(arr->datas[index]);
    arr->datas[index] = data;
    return 0;
}
/// @brief 插入新数据到数组指定下标
/// @param arr
/// @param index 小于数组长度的下标
/// @param data 新元素地址
/// @return
int array_insert(array_t *arr, size_t index, void *data)
{
    if (arr == NULL || index >= arr->len)
        return -1;
    if (arr->len + 1 >= arr->cap)
    {
        int ret = __array_enlarging(&arr, arr->cap + array_enlarging_cap);
        if (ret)
            return ret;
    }
    size_t start = index;
    size_t end = arr->len;
    // 批量后移
    while (start <= end)
    {
        arr->datas[end + 1] = arr->datas[end];
        end--;
    }

    arr->datas[index] = data;
    arr->len++;
    return 0;
}
/// @brief 获取数组指定下标 元素地址
/// @param arr
/// @param index
/// @return 元素地址
void *array_get(array_t *arr, size_t index)
{
    if (arr == NULL || index >= arr->len)
        return NULL;
    return arr->datas[index];
}
/// @brief 批量追加新元素
/// @param src 被追加数组
/// @param dst 追加数组
/// @return
int array_append(array_t *src, array_t *dst)
{
    if (src == NULL || dst == NULL)
        return -1;
    for (size_t i = 0; i < dst->len; i++)
    {
        int ret = array_add(src, array_get(dst, i));
        if (ret)
            return ret;
    }
    return 0;
}
/// @brief 批量追加新元素
/// @param arr 被追加数组
/// @param datas 存放元素地址的数组
/// @param data_len 存放元素地址的数组长度
/// @return
int array_append1(array_t *arr, void **datas, size_t data_len)
{
    if (arr == NULL)
        return -1;
    for (size_t i = 0; i < data_len; i++)
    {
        int ret = array_add(arr, datas[data_len]);
        if (ret)
            return ret;
    }
    return 0;
}

/// @brief 销毁动态数组
/// @param ptr array_t 地址
void array_deinit(array_t **ptr)
{
    if (*ptr == NULL)
        return;
    array_t *arr = *ptr;
    if (arr->deinit_before != NULL)
    {
        for (size_t i = 0; i < arr->len; i++)
        {
            arr->deinit_before(arr->datas[i]);
        }
    }
    free(arr->datas);
    free(arr);
    *ptr = NULL;
}